/**
 * Copyright 1996 self.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 *
 * @author Ashin Wimalajeewa
 *
 * Note, this is a very old runtime library that I have evolved since 1996. I rarely use it
 * now because the Apache Commons project has made it obsolete.
 */
package self.gee.editor;

import self.util.FifoList;

public class CommandManager {
  private FifoList history = new FifoList( 20 );
  private int redoPosition = -1;
  
  public void execute( ICommand cmd, boolean preExecuted ) {
    int currRedo = redoPosition;
    releaseRedoBuffer();
    history.add( cmd );
    try {
      if ( !preExecuted )
        cmd.execute();
    } catch ( RuntimeException err ) {
      redoPosition = currRedo;
      throw err;
    }
//    System.out.println("cmd::hist->" + history );
  }
  
  public ICommand undo() {
    if ( !canUndo() ) 
      return null;
    
    ICommand cmd = (ICommand) history.get( redoPosition-- );
//    System.out.println("undo->" + cmd );
    cmd.undo();
    return cmd;
  }
  
  public ICommand redo() {
    if ( !canRedo() ) 
      return null;
    ICommand cmd = (ICommand) history.get( ++redoPosition );
//    System.out.println("redo->" + cmd );
    cmd.execute();
    return cmd;
  }
  
  public boolean canUndo() {
    return redoPosition >= 0;
  }
  
  public boolean canRedo() {
    return redoPosition >= -1 && redoPosition < history.size()-1;
  }
  
  private void releaseRedoBuffer() {
    int max = history.size();
    if ( redoPosition == max-1 ) {
      if ( redoPosition < history.maxSize()-1 )
        redoPosition++;
      return;
    }
    for ( int cntr = max-1; cntr > redoPosition; cntr-- )
      history.remove( cntr );
    redoPosition = history.size();
  }
  
  
//  static public void main( String[] args ) {
//    abstract class MathCmd implements ICommand {
//      protected int[] env;
//      protected int by;
//      
//      public MathCmd( int[] val, int by ) {
//        env = val;
//        this.by = by;
//      }
//      
//      public String toString() {
//        return "<" + this.getClass().getName() + ":by=" + by + ">\n";
//      }
//    };
//    class AddCmd extends MathCmd {
//      public AddCmd( int[] val, int by ) { super( val, by ); }
//      public void execute() {
//        env[0] = env[0] + by;
//      }
//      public String undo() {
//        env[0] = env[0] - by;
//        return null;
//      }
//    };
//    class MinusCmd extends MathCmd {
//      public MinusCmd( int[] val, int by ) { super( val, by ); }
//      public void execute() {
//        env[0] = env[0] - by;
//      }
//      public String undo() {
//        env[0] = env[0] + by;
//        return null;
//      }
//    };
// 
//    int[] result = { 0 };
//    CommandManager mgr = new CommandManager();
//    ICommand cmd;
//
//    cmd = new AddCmd( result, 100 );
//    mgr.execute( cmd, false );
//    
//    cmd = new AddCmd( result, 250 );
//    mgr.execute( cmd, false );
//    
//    cmd = new MinusCmd( result, 50 );
//    mgr.execute( cmd, false );
//    
//    cmd = new AddCmd( result, 25 );
//    mgr.execute( cmd, false );
//    
//    cmd = new MinusCmd( result, 10 );
//    mgr.execute( cmd, false );
//    
//    cmd = new MinusCmd( result, 10010 );
//    mgr.execute( cmd, false );
//    
//    mgr.undo();
//    mgr.undo();
//    mgr.undo();
//    mgr.redo();
//    mgr.redo();
//    mgr.undo();
//    
//    cmd = new AddCmd( result, 75 );
//    mgr.execute( cmd, false );
//    
//    cmd = new MinusCmd( result, 10 );
//    mgr.execute( cmd, false );
//
//    mgr.undo();
//    
//    System.out.println("result = " + result[0]);
//
//    for ( int cntr = 0; cntr < 18; cntr++ ) 
//      mgr.undo();
//    
// //    mgr.undo();
// //    mgr.undo();
// //    mgr.undo();
// //    mgr.undo();
// //    mgr.undo();
// //    mgr.undo();
//    System.out.println("result = " + result[0]);
//
//    for ( int cntr = 0; cntr < 18; cntr++ ) {
//      mgr.redo();
//    }
//    System.out.println("result = " + result[0]);
//  }


//  static public void main( String[] args ) {
//    abstract class MathCmd implements ICommand {
//      protected int[] env;
//      protected int by;
//      
//      public MathCmd( int[] val, int by ) {
//        env = val;
//        this.by = by;
//      }
//      
//      public String toString() {
//        return "<" + this.getClass().getName() + ":by=" + by + ">\n";
//      }
//    };
//    class AddCmd extends MathCmd {
//      public AddCmd( int[] val, int by ) { super( val, by ); }
//      public void execute() {
//        env[0] = env[0] + by;
//      }
//      public void undo() {
//        env[0] = env[0] - by;
//        return;
//      }
//    };
//    class MinusCmd extends MathCmd {
//      public MinusCmd( int[] val, int by ) { super( val, by ); }
//      public void execute() {
//        env[0] = env[0] - by;
//      }
//      public void undo() {
//        env[0] = env[0] + by;
//        return;
//      }
//    };
// 
//    int[] result = { 0 };
//    CommandManager mgr = new CommandManager();
//    ICommand cmd;
//    
//    for ( int cntr = 0; cntr < 25; cntr++ ) {
//      cmd = new AddCmd( result, cntr );
//      mgr.execute( cmd, false);
//  //      if ( cntr % 5 == 0 ) {
//  //        mgr.undo();
//  //      }
//    }
//
//    while ( mgr.canUndo() )
//      mgr.undo();
//      
//    System.out.println("result = " + result[0]);
//  }
}